﻿using System;
using System.Linq;
using System.Windows.Browser;
using System.Text;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Xml.Linq;

namespace SilverQuery
{
	public delegate void AjaxCallback(string responseText, AjaxException error);

	/// <summary>
	/// Library of Utility methods for performing jQuery-like ajax calls.
	/// </summary>
	public static class Ajax
	{
		/// <summary>
		/// Load a remote page using an HTTP GET request.
		/// </summary>
		/// <param name="url">The URL of the HTML page to load.</param>
		/// <param name="data">Key/value pairs that will be sent to the server.</param>
		/// <param name="callback">The method called when the ajax request is complete (not necessarily success).</param>
		public static void get(string url, IDictionary<string, object> data, AjaxCallback callback)
		{
			Uri uri = MakeUrl(url);
			WebClient client = new WebClient();
			if (data != null)
			{
				var builder = new UriBuilder(uri);
				builder.Query = FormatHttpData(data);
				uri = builder.Uri;
			}

			client.DownloadStringCompleted += (sender, e) =>
				{
					if (e.Error != null)
						callback(null, new AjaxException("Exception making get request to " + uri.ToString(), uri, e.Error));
					else
						callback(e.Result, null);
				};

			client.DownloadStringAsync(uri);
		}

		/// <summary>
		/// Load a remote page using an HTTP POST request.
		/// </summary>
		/// <param name="url">The URL to post to.</param>
		/// <param name="data">The key/value pairs to post back to the server.</param>
		/// <param name="callback">The method called when the ajax request is complete (not necessarily success).</param>
		public static void post(string url, IDictionary<string, object> data, AjaxCallback callback)
		{
			Uri uri = MakeUrl(url);
			WebClient client = new WebClient();
			client.UploadStringCompleted += (sender, e) =>
				{
					if (e.Error != null)
						callback(null, new AjaxException("Error making POST request to " + uri.ToString(), uri, e.Error));
					else
						callback(e.Result, null);
				};
			client.UploadStringAsync(uri, FormatHttpData(data));
		}

		/// <summary>
		/// Make a <see cref="Uri"/> from the url path string.
		/// </summary>
		public static Uri MakeUrl(string path)
		{
			if (path.StartsWith("http"))
				return new Uri(path);

			var current = HtmlPage.Document.DocumentUri;
			var builder = new UriBuilder(current.Host);
			builder.Port = current.Port;

			if (path.StartsWith("/"))
				builder.Path = path;
			else
			{
				builder.Path = current.AbsolutePath.Substring(0, current.AbsolutePath.LastIndexOf('/') + 1) + path;
			}
			return builder.Uri;
		}

		private static string FormatHttpData(IDictionary<string, object> data)
		{
			if (data == null)
				return string.Empty;

			StringBuilder sb = new StringBuilder();
			var keys = data.Keys;
			for (int i = 0; i < keys.Count; i++)
			{
				string key = keys.ElementAt(i);
				if (i > 0)
					sb.Append("&");
				sb.AppendFormat("{0}={1}", key, HttpUtility.UrlEncode(data[key].ToString()));
			}
			return sb.ToString();
		}
	}

	public class AjaxException : System.Net.WebException
	{
		internal AjaxException(string message, Uri url, Exception inner) : base(message, inner)
		{
			this.Url = url;
		}

		public Uri Url
		{
			get;
			private set;
		}
	}
}
